// created by noellynch
// Jun 5, 2009

package com.sceneworker.editors.glslshadereditor.glslcodepanel;

import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JTextPane;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Position;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
import javax.swing.text.TabSet;
import javax.swing.text.TabStop;

import com.sceneworker.util.swing.sourcecompletionpanel.ICodeCompletionKeyWord;

public class GLSLFormattedTextPane extends JTextPane {

	private	static		final	Color		COMMENTS_COLOUR = new Color(63, 127, 95);
	private	static		final	Color		KEYWORDS_COLOUR = new Color(127, 0, 85);
	
	public	GLSLFormattedTextPane() {
		super();
		
		setForeground(Color.blue);
		
		Style lcl_commentStyle = addStyle("Comment", null);
	    StyleConstants.setForeground(lcl_commentStyle, COMMENTS_COLOUR);
	    
	    Style lcl_keyWordStyle = addStyle("KeyWord", null);
	    StyleConstants.setBold(lcl_keyWordStyle, true);
	    StyleConstants.setForeground(lcl_keyWordStyle, KEYWORDS_COLOUR);
	    
	    addKeyListener(new KeyListener() {
			public void keyPressed(KeyEvent cl_e) {
				if(cl_e.getKeyCode() == KeyEvent.VK_ENTER) {
					cl_e.consume();
					indent();
				}
				format();
			}

			public void keyReleased(KeyEvent e) {
			}

			public void keyTyped(KeyEvent cl_e) {
			}
	    });
	}
	
	private	int		count(String str_sequence, String str_src) {
		int		li_cnt = 0;
		
		int		li_offset = 0;
		
		while(li_offset != -1) {
			li_offset = str_src.indexOf(str_sequence, li_offset);
			
			if(li_offset != -1) {
				li_cnt++;
				li_offset += str_sequence.length();
			}
		}
		
		return li_cnt;
	}
	
	public	void	indent() {
		int			li_tab = 0;
		int			li_caret = getCaretPosition();
		String		lstr_temp = getText();
		
		int			li_cntOpen = count("{", lstr_temp.substring(0, li_caret));
		int			li_cntClose = count("}", lstr_temp.substring(0, li_caret));
		
		li_tab = li_cntOpen - li_cntClose;
		
		String	lstr_tab = "\n";
		for(int li_indx = 0; li_indx < li_tab; li_indx++) {
			lstr_tab += "\t";
		}
		
		insert(lstr_tab, li_caret);
		setCaretPosition(li_caret + lstr_tab.length());
	}
	
	public void setTabs(int charactersPerTab) {
		FontMetrics fm = getFontMetrics(getFont());
		int charWidth = fm.charWidth( 'w' );
		int tabWidth = charWidth * charactersPerTab;
 
		TabStop[] tabs = new TabStop[10];
 
		for (int j = 0; j < tabs.length; j++)
		{
			int tab = j + 1;
			tabs[j] = new TabStop( tab * tabWidth );
		}
 
		TabSet tabSet = new TabSet(tabs);
		SimpleAttributeSet attributes = new SimpleAttributeSet();
		StyleConstants.setTabSet(attributes, tabSet);
		int length = getDocument().getLength();
		getStyledDocument().setParagraphAttributes(0, length, attributes, false);
	}
	
	public void replaceRange(String str, int start, int end) {
        if (end < start) {
            throw new IllegalArgumentException("end before start");
        }
        Document doc = getDocument();
        if (doc != null) {
            try {
                if (doc instanceof AbstractDocument) {
                    ((AbstractDocument)doc).replace(start, end - start, str,
                                                    null);
                }
                else {
                    doc.remove(start, end - start);
                    doc.insertString(start, str, null);
                }
            } catch (BadLocationException e) {
                throw new IllegalArgumentException(e.getMessage());
            }
        }
    }
	
	public void insert(String str, int pos) {
        Document doc = getDocument();
        if (doc != null) {
            try {
                doc.insertString(pos, str, null);
            } catch (BadLocationException e) {
                throw new IllegalArgumentException(e.getMessage());
            }
        }
    }
	
	private	void	formatRange(String str_st, String str_end, Style cl_style, boolean b_includeEnd) {
		StyledDocument lcl_doc = getStyledDocument();
		String		lstr_temp = getText();
		
		int		li_offset = 0;
		
		while(li_offset != -1) {
			li_offset = lstr_temp.indexOf(str_st, li_offset);
			
			if(li_offset != -1) {
				int		li_end = lstr_temp.indexOf(str_end, li_offset);
				if(li_end != -1) {
					if(b_includeEnd) {
						li_end += str_end.length();
					}
					
					lcl_doc.setCharacterAttributes(li_offset, li_end - li_offset, cl_style, true);
					li_offset = li_end;
				} else {
					lcl_doc.setCharacterAttributes(li_offset, lstr_temp.length() - li_offset, cl_style, true);
					li_offset = -1;
				}
			}
		}
	}
	
	private	void	formatComments() {
		formatRange("//", "\n", getStyle("Comment"), false);
		formatRange("/*", "*/", getStyle("Comment"), true);
		/*StyledDocument lcl_doc = getStyledDocument();
		String		lstr_temp = getText();
		
		int		li_offset = 0;
		
		while(li_offset != -1) {
			li_offset = lstr_temp.indexOf("//", li_offset);
			
			if(li_offset != -1) {
				int		li_eol = lstr_temp.indexOf("\n", li_offset);
				if(li_eol != -1) {
					lcl_doc.setCharacterAttributes(li_offset, li_eol - li_offset, getStyle("Comment"), true);
					li_offset = li_eol;
				} else {
					lcl_doc.setCharacterAttributes(li_offset, lstr_temp.length() - li_offset, getStyle("Comment"), true);
					li_offset = -1;
				}
			}
		}*/
	}
	
	private	void	formatKeyWords() {
		for(ICodeCompletionKeyWord lcl_part : GLSLKeyWordsArray.inst().getGLSLCompletionParts()) {
			if(lcl_part.isKeyWord()) {
				formatKeyWord(lcl_part.getPart());
			}
		}
	}
	
	private	void	formatKeyWord(String str_keyWord) {
		StyledDocument lcl_doc = getStyledDocument();
		String		lstr_temp = getText();
		
		int		li_offset = 0;
		
		while(li_offset != -1) {
			li_offset = lstr_temp.indexOf(str_keyWord, li_offset);
			
			if(li_offset != -1) {
				lcl_doc.setCharacterAttributes(li_offset, str_keyWord.length(), getStyle("KeyWord"), true);
				li_offset += str_keyWord.length();
			}
		}
	}
	
	public	void	format() {
		StyledDocument lcl_doc = getStyledDocument();
		Position		lcl_start = lcl_doc.getStartPosition();
		
		formatKeyWords();
		formatComments();
		
		repaint();
	}
}
